package distlock;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.params.SetParams;

import java.util.Collections;

/**
 * 分布式锁
 * 1. 互斥性：只有一个客户端能够持有锁nx
 * 2. 不会产生死锁：即使持有锁的客户端崩溃，也能保证后续其他客户端可以获取锁expire
 * 3. 只有持有这把锁的客户端才能解锁
 * @author:         MI
 * @email:          448341911@qq.com
 * @createTime:     2025/8/17 18:18
 * @updateUser:     MI
 * @updateTime:     2025/8/17 18:18
 * @updateRemark:   修改内容
 * @version:        1.0
 */
public class DistLock {
    private static final String LOCK_SUCCESS = "OK";
    private static final String SET_IF_NOT_EXIST = "NX";
    private static final String SET_WITH_EXPIRE_TIME = "PX";
    private static final Long RELEASE_SUCCESS = 1L;
    // 条件：设置过期时间单位为“秒”（EX = Seconds）；若需毫秒，用 px()
    private static final SetParams SET_WITH_EXPIRE_TIME_EX = SetParams.setParams().ex(0); // 过期时间后续动态赋值

    /**
     * 适配 Jedis 5.2.0 的分布式锁获取方法（使用 SetParams）
     * @param jedis Redis 客户端
    /**
     * 尝试获取分布式锁
     * @param jedis Redis客户端
     * @param lockKey 锁
     * @param requestId 请求标识
     * @param expireTime 超期时间
     * @return 是否获取成功
     */
//    public static boolean tryGetDistributedLock(Jedis jedis, String lockKey, String requestId, int expireTime) {
//        // set支持多个参数 NX（not exist） XX（exist） EX（seconds） PX（million seconds）
//        String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
//        if (LOCK_SUCCESS.equals(result)) {
//            return true;
//        }
//        return false;
//    }

    /**
     * 适配 Jedis 5.2.0 的分布式锁获取方法（使用 SetParams）
     * @param jedis Redis 客户端
     * @param lockKey 锁的 Key
     * @param requestId 请求标识（用于后续释放锁时验证身份，避免误删）
     * @param expireTime 锁的过期时间（单位：秒，与 EX 对应；若用 PX 则为毫秒）
     * @return 是否获取锁成功
     */
    public static boolean tryGetDistributedLock(Jedis jedis, String lockKey, String requestId, int expireTime) {
        // 1. 封装加锁条件：NX（键不存在才加锁） + EX（过期时间单位秒） + 具体过期时间
        SetParams setParams = SetParams.setParams()
                .nx()          // 等价于旧版本的 SET_IF_NOT_EXIST
                .ex(expireTime); // 等价于旧版本的 SET_WITH_EXPIRE_TIME + 过期时间（直接传入秒数）

        // 2. 执行 set 命令（原子操作：加锁+设置过期时间）
        String result = jedis.set(lockKey, requestId, setParams);

        // 3. 判断结果：返回 OK 表示加锁成功
        return LOCK_SUCCESS.equals(result);
    }
    /**
     * 释放分布式锁
     * @param jedis Redis客户端
     * @param lockKey 锁
     * @param requestId 请求标识
     * @return 是否释放成功
     */
    public static boolean releaseDistributedLock(Jedis jedis, String lockKey, String requestId) {
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));

        if (RELEASE_SUCCESS.equals(result)) {
            return true;
        }
        return false;
    }
}
